/** 
 * @file Director.h 
 * 
 * @brief  Declares the Director
 * @author Bas du Pre
 * @date   16-05-2011
 * 
 **/ 

#pragma once

#include "../global.h"

#include "Scene.h"
#include "Label.h"
#include "DebugLayer.h"

namespace Prism {    
namespace Graphics {

    /**
     * \nosubgrouping
     * \brief <tt>[singleton]</tt> Class that manages the whole framework.
     *
     * The Director handles the main window, manages scenes and is used to 
     * interface with the Operating System.
     *
     * \note The Director is a singleton. The standard way to use it is by calling
     *       Director::instance(). theDirector() can be used as a shortcut for the
     *       Director instance.
     */
    class Director : public PObject {
        
        Director();
        void init();
        virtual ~Director();
        
        static Director *s_instance;
        
    public:
        /**
         * \brief  Returns the singleton instance of the Director.
         * \return The director instance
         * \todo   The Director should only be created by the AppDelegate. This function
         *         shoud throw a PRISM_ERROR if the Director has not yet been created.
         */
        static Director *instance();
        /**
         * \brief Whether or not the Director instance has been initialized yet.
         *  \note The Director instance gets created when it's needed. In early stages of
         *        execution it is possible that the Director has not yet been created.
         *        Sometimes you should not want the Director to be created yet,
         *        especially before calling the prism_initialize() function. 
         *            
         */
        static bool isCreated();
        
        ///\name Properties 
        ///\{
        /**
         * \brief Returns the size of the main window.
         */
        Size winSize();
        /**
         * \brief Sets the size of the main window.         
         * \fires onWinSizeChanged
         *
         * This function resizes the main window.
         *
         * \todo  This function should throw an PRISM_ERROR when changing the 
         *        size of the main window is not possible on this platform (e.g. on iOS).
         */
        void setWinSize(Size size);
        
        /**
         * \brief Returns whether the debug layer is visible.
         */
        bool showDebugLayer();
        /**
         * \brief Turns the debug layer on or off.
         */
        void setShowDebugLayer(bool showDebugLayer);
        
        /**
         * \brief Limit the maximum framerate.
         * 
         * This also limits the interval between onUpdate event calls.
         * \note The maximum framerate is just an indication to Prism.
         *       Depending on the platform and the implementation this can be 
         *       completely ignored or not as accurate as expected. Please make
         *       sure to always act upon the delta parameter for the onUpdate event
         *        arguments.
         */
        void setMaxFrameRate(PInt maxFrameRate);
        /**
         * \brief Get the maximum framerate.
         */
        PInt maxFrameRate();
        
        ///\}
        
        /**
         * \brief Returns the currently running scene.
         * \return A pointer to the currently running Scene or 0 if no scene is running.
         */
        Scene *runningScene();
        
        /**
         * \brief Whether the engine is paused.
         */
        bool isPaused();
        
        // Methods
        /**
         * \brief Starts the engine and runs the scene.
         * \param scene The Scene to run.
         * \fires onSceneChanged
         * 
         * The Scene stack will be cleared and \c scene will be pushed on the stack.
         */
        void runWithScene(Scene *scene);
        
        /** \brief Pushes a Scene to the top of the stack.
         *  \param scene The Scene
         *  \fires onSceneChanged
         */
        void pushScene(Scene *scene);
        
        /**
         * \brief Pops a Scene from the top of the stack.
         * \fires onSceneChanged
         */
        void popScene();
        
        /**
         * \brief Replaces the Scene on the top of the stack.
         * \param scene The Scene
         * \fires onSceneChanged
         * 
         * Throws a PRISM_ERROR when the stack is empty.
         */
        void replaceScene(Scene *scene);
        
        /**
         * \brief Ends the exectution of the application.
         * \fires onTerminating
         */
        void end();
        
        /**
         * \brief Pause the engine
         * \fires onPaused
         */
        void pause();
        
        /**
         * \brief Resume the engine if paused.
         * \fires onResumed
         */
        void resume();
        
        /// Returns the current FPS.
        PFloat fps();
        
        ///\cond INTERNAL
        virtual void drawScene();
        ///\endcond
        
        /// String representation of the Director.
        virtual String toString();
        
        ///\name Events 
        ///\{
        Event<EventArgs*> onInitialized;
        Event<EventArgs*> onPaused;
        Event<EventArgs*> onResumed;
        Event<EventArgs*> onTerminating;
        Event<EventArgs*> onSceneChanged;
        Event<EventArgs*> onWinSizeChanged;
        ///\}
        
        #if PRISM_OS_IOS && PRISM_BUILDENGINE
        #include "iOS/ios_Director.h"
        #elif PRISM_TARGET_SDL
        #include "sdl/sdl_Director.h"
        #endif
        
    private:
        Scene *_scene;
        DebugLayer *_debugLayer;
        Size _winSize;
        bool _showDebugLayer;
        PInt _maxFramerate;
        
        virtual PFloat native_fps();
        virtual void native_sceneUpdate();
        
        virtual void native_beforeDrawScene();
        virtual void native_afterDrawScene();
    };
    
    /**
     * \brief   Shortcut to Director::instance().
     * \relates Director
     */
    Director* theDirector();
}
}

